﻿using System;
using System.Collections.Generic;
using System.IO;
using LingDong.IndexEntities;
using LingDong.SerializeProvider;
using LingDong.IndexEntities.Helper;
using LingDong.IndexEntities.Document;

namespace LingDong.IndexReader
{
    internal class DocumentIndex : IDisposable
    {
        #region Constructors

        internal DocumentIndex()
        {
            LoadFromFile(
                IndexNameHelper.GetDocumentIndexFileName(), 
                IndexNameHelper.GetParsedDocumentFileName(), 
                IndexNameHelper.GetOriginalDocumentFileName());
        }

        /// <summary>
        /// Load document index from index files
        /// </summary>
        /// <param name="docIndexFname"></param>
        /// <param name="parsedDocFname"></param>
        /// <param name="oriDocFname"></param>
        private void LoadFromFile(string docIndexFname, string parsedDocFname, string oriDocFname)
        {
            // deserialize document offset
            using (FileStream fs = new FileStream(docIndexFname, FileMode.Open))
            {
                documentOffset = Serializer.Deserialize<Dictionary<int, DocumentOffset>>(fs);
            }

            // open document index files
            parsedDocumentStream = new FileStream(parsedDocFname, FileMode.Open);
            originalDocumentStream = new FileStream(oriDocFname, FileMode.Open);
        }

        #endregion
        

        #region Index Reader Methods

        internal ParsedDocumentEntity GetParsedDocumentByID(int docID)
        {
            if (!documentOffset.ContainsKey(docID))
                return null;

            parsedDocumentStream.Position = documentOffset[docID].ParsedDocumentOffset; ;
            return Serializer.Deserialize<ParsedDocumentEntity>(parsedDocumentStream);
        }

        internal OriginalDocumentEnity GetOriginalDocumentByID(int docID)
        {
            if (!documentOffset.ContainsKey(docID))
                return null;

            originalDocumentStream.Position = documentOffset[docID].OriginalDocumentOffset;
            return Serializer.Deserialize<OriginalDocumentEnity>(originalDocumentStream);
        }

        internal int GetMaxDocumentID()
        {
            return documentOffset.Count;
        }

        internal double GetDocumentRank(int docID)
        {
            if (!documentOffset.ContainsKey(docID))
                return 0.0;

            return GetParsedDocumentByID(docID).Rank;
        }

        #endregion
        

        #region Disposable Related

        ~DocumentIndex()
        {
            Dispose();
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            // protect from being called multiple times.
            if (disposed)
            {
                return;
            }

            if (disposing)
            {
                // clean up all managed resources.
                if (parsedDocumentStream != null)
                {
                    parsedDocumentStream.Dispose();
                }
                if (originalDocumentStream != null)
                {
                    originalDocumentStream.Dispose();
                }
            }

            disposed = true;
        }

        private bool disposed = false;

        #endregion
        

        #region Private Members

        private FileStream parsedDocumentStream;
        private FileStream originalDocumentStream;

        /// <summary>
        /// [DocID, (parsed doc offset, ori doc offset)]
        /// </summary>        
        private Dictionary<int, DocumentOffset> documentOffset;

        #endregion
    }
}
